package org.digitarts.rtms.spring.collectors.shell.commands;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.digitarts.rtms.helpers.XMLHelper;
import org.digitarts.rtms.spring.collectors.shell.IShell;
import org.digitarts.rtms.tracing.Trace;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;


public class CommandSet implements BeanNameAware, BeanFactoryAware
{
	protected String				name					= null;
	protected Map<String, Command>	commands				= new HashMap<String, Command>();
	protected Logger				log						= null;
	protected String				beanName				= null;
	protected BeanFactory			beanFactory				= null;
	protected boolean				commandBeanFactoriesSet	= false;

	public CommandSet()
	{
		log = Logger.getLogger(getClass());
	}

	public CommandSet(File configPath) throws IOException
	{
		this(XMLHelper.parseXML(configPath.toURI().toURL().openStream()).getDocumentElement());
	}

	public CommandSet(URL configUrl) throws IOException
	{
		this(XMLHelper.parseXML(configUrl.openStream()).getDocumentElement());
	}

	public CommandSet(String xml)
	{
		this(XMLHelper.parseXML(xml).getDocumentElement());
	}

	public CommandSet(Element xml)
	{
		name = XMLHelper.getAttributeValueByName(xml, "name");
		log = Logger.getLogger(getClass().getName() + "." + name);
		Node commandsNode = XMLHelper.getChildNodeByName(xml, "Commands", false);
		if (commandsNode != null)
		{
			List<Node> cNodes = XMLHelper.getChildNodesByName(commandsNode, "Command", false);
			for (Node node : cNodes)
			{
				Command command = new Command((Element) node);
				commands.put(command.getShellCommand(), command);
			}
		}
	}

	public static CommandSet valueOf(String xml)
	{
		return new CommandSet(xml);
	}

	public Set<Trace> processCommands(IShell shell, Map<String, ?>... context) throws Exception
	{
		Set<Trace> results = new HashSet<Trace>();
		for (Command command : commands.values())
		{
			long start = System.currentTimeMillis();
			if (!commandBeanFactoriesSet)
			{
				command.setBeanFactory(beanFactory);
				commandBeanFactoriesSet = true;
			}
			String result = shell.issueOSCommand(command.getShellCommand(), context);
			long commandElapsed = System.currentTimeMillis() - start;
			start = System.currentTimeMillis();
			if (result != null)
			{
				results.addAll(command.processResult(result));
			}
			long parsingElapsed = System.currentTimeMillis() - start;
			if (log.isDebugEnabled())
				log.debug("CommandExec:[" + command.getShellCommand() + "]\n\tCommand Time:" + commandElapsed + " ms.\n\tParsing Time:" + parsingElapsed + " ms.");
		}
		return results;
	}

	public Command getCommand(String name)
	{
		return commands.get(name);
	}

	public static void main(String[] args)
	{
		Document d = XMLHelper.parseXML(new File("C:/projects3.3/RuntimeMonitoring/commands/xml/SuseLinux9.xml"));
		CommandSet cs = new CommandSet(d.getDocumentElement());
		System.out.println(cs);
		for (Command command : cs.commands.values())
		{
			log("=====Command======");
			log(command);
			for (CommandResultExtract cre : command.extracts)
			{
				log("=====CommandResultExtract======");
				log(cre);
			}
		}
	}

	public static void log(Object message)
	{
		System.out.println(message);
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final CommandSet other = (CommandSet) obj;
		if (name == null)
		{
			if (other.name != null)
				return false;
		}
		else if (!name.equals(other.name))
			return false;
		return true;
	}

	public String toString()
	{
		final String TAB = "    \n\t";

		StringBuilder retValue = new StringBuilder();

		retValue.append("CommandSet ( ").append("name = ").append(this.name).append(TAB).append("commands=").append(this.commands.size()).append("\n\t").append(" )");
		return retValue.toString();
	}

	public void setBeanName(String beanName)
	{
		this.beanName = beanName;
	}

	public String getBeanName()
	{
		return beanName;
	}

	public void setBeanFactory(BeanFactory beanFactory) throws BeansException
	{
		this.beanFactory = beanFactory;

	}

}
